home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’97
/
Jasik Park - The Lost UI
/
JasikAppearance
/
JasikAppearance.cpp
< prev
next >
Wrap
Text File
|
1997-06-28
|
14KB
|
571 lines
// JasikLookHack - ©1997 by Marc Sherman
#include "Types.h"
#include "QuickDraw.h"
#include "Windows.h"
#include "Memory.h"
#include "Resources.h"
#include "OSUtils.h"
#include "LowMem.h"
#include "Files.h"
#include "SetupA4.h"
#include "A4Stuff.h"
#define ASSERT(cond) do{if(!cond) DebugStr("\p" #cond);}while(false)
#define VERIFY(cond) do{if(!cond) DebugStr("\p" #cond);}while(false)
#define OS_VERIFY(func) do{OSErr err = (func); ASSERT(err == noErr);}while(false)
// The icon for the init to load
const short kIconFamilyID = -834;
const long kUpdateTicks = 60;
const short kTaskMenuID = -834;
// Type definitions for trap patches
typedef pascal void (*InsertMenuProcPtr)(MenuRef theMenu, short beforeID);
typedef pascal void (*SystemTaskProcPtr)(void);
typedef pascal Handle (*GetResourceProcPtr)(ResType rType, short rID);
typedef pascal void (*SetMenuItemTextProcPtr)(MenuRef theMenu, short item, ConstStr255Param itemString);
typedef pascal long (*MenuSelectProcPtr)(Point startPt);
// Global variables for original trap addresses
InsertMenuProcPtr gOldInsertMenu;
SystemTaskProcPtr gOldSystemTask;
GetResourceProcPtr gOldGetResource;
SetMenuItemTextProcPtr gOldSetMenuItemText;
MenuSelectProcPtr gOldMenuSelect;
static short gMyRefNum = 0;
//---------------------------------------------------------------------------
// Compare two pascal strings
//---------------------------------------------------------------------------
static Boolean PStrEqu(const StringPtr a, const StringPtr b)
{
if(*a == *b)
{
for(int i = *a; i > 0; i--)
{
if(a[i] != b[i])
{
return false;
}
}
return true;
}
return false;
}
//---------------------------------------------------------------------------
// Is this the Finder?
//---------------------------------------------------------------------------
static Boolean IsFinder()
{
// Bail if we're in the system still - curapname probably isn't init'ed
if(LMGetCurApRefNum() == 0)
return true;
const StringPtr curApp = LMGetCurApName();
const StringPtr finderName = "\pFinder";
return PStrEqu(curApp, finderName);
}
//---------------------------------------------------------------------------
// RetitleAppleMenu to the memory size (using unofficially documented menu list structs)
//---------------------------------------------------------------------------
struct MenuRec
{
MenuHandle menuOH;
short menuLeft;
};
struct DynamicMenuList
{
short lastMenu;
short lastRight;
short mbResID;
MenuRec menu[1];
};
static void SetMenuTitle(MenuHandle hMenu, StringPtr newTitle)
{
// Bail if the new title equals the old title
if(PStrEqu(newTitle, hMenu[0]->menuData))
return;
// Calculate the current length of the title text
int oldTitleLength = hMenu[0]->menuData[0];
int newTitleLength = newTitle[0];
// Calc the new size of the handle
int oldHandleSize = GetHandleSize((Handle)hMenu);
int newHandleSize = oldHandleSize - oldTitleLength + newTitleLength;
// Calc the positions of the item defs
Ptr oldItemDefPos = (Ptr)(hMenu[0]->menuData) + oldTitleLength + 1;
// Buffer the item defs (in case we're shrinking the handle size)
int bufferSize = oldHandleSize - (oldItemDefPos - (Ptr)(*hMenu));
Ptr defBuffer = NewPtr(bufferSize);
BlockMoveData(oldItemDefPos, defBuffer, bufferSize);
// Resize the handle
SetHandleSize((Handle)hMenu, newHandleSize);
// Modify the menu name
BlockMoveData(newTitle, hMenu[0]->menuData, newTitleLength + 1);
// Copy the buffered item defs from the buffer
Ptr newItemDefPos = (Ptr)(hMenu[0]->menuData) + newTitleLength + 1;
BlockMoveData(defBuffer, newItemDefPos, bufferSize);
// Free the buffer
DisposePtr(defBuffer);
// Draw the new menu bar next time through the event loop
InvalMenuBar();
}
static void RetitleAppleMenu()
{
static long callCount = 0;
// Get the apple (first) menu
DynamicMenuList** hMbar = (DynamicMenuList**)LMGetMenuList();
ASSERT(hMbar);
ASSERT(*hMbar);
// Only fiddle if there's a menu in the list
if(hMbar[0]->lastMenu)
{
MenuHandle hAppleMenu = hMbar[0]->menu[0].menuOH;
ASSERT(hAppleMenu);
ASSERT(*hAppleMenu);
// Init the new title
Str255 newTitle = "\pfreeK ";
if(callCount++ >= 20)
{
long freeK = 0;
// Get the amount of memory free in the app or temp heap
if(IsFinder())
freeK = TempFreeMem() / 1024;
else
freeK = FreeMem() / 1024;
// Get the new title
NumToString(freeK, newTitle);
newTitle[++newTitle[0]] = 'K';
}
SetMenuTitle(hAppleMenu, newTitle);
}
}
inline char LowerChar(char c)
{
if(c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
else
return c;
}
inline char UpperChar(char c)
{
if(c >= 'a' && c <= 'z')
return c - 'a' + 'A';
else
return c;
}
inline char IsVowel(char c)
{
switch(LowerChar(c))
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
}
return false;
}
static void RandomMenuItemStyle(MenuHandle hMenu, short item)
{
Str255 theString;
GetMenuItemText(hMenu, item, theString);
// Bail if the string is 0-length
if(theString[0] == 0)
return;
// hash the string text in lower case
unsigned long strHash = 0;
for(int i = 1; i <= theString[0]; i++)
strHash += LowerChar(theString[i]);
switch(strHash % 10)
{
case 0:
// don't touch the capitalization
break;
case 1:
case 2:
case 3:
case 4:
// lowercase the first letter
theString[1] = LowerChar(theString[1]);
break;
case 5:
// remove some vowels
int newLen = 0;
int spaces = 0;
for(int srcChar = 1; srcChar <= theString[0]; srcChar++)
{
if(theString[srcChar] == ' ')
spaces++;
if((spaces % 2) || !IsVowel(theString[srcChar]))
theString[++newLen] = theString[srcChar];
}
theString[0] = newLen;
break;
case 6:
// capitalize the menu
for(int i = 1; i <= theString[0]; i++)
{
theString[i] = UpperChar(theString[i]);
}
break;
case 7:
case 8:
case 9:
// Bold the menu
SetItemStyle(hMenu, item, bold);
break;
}
(*gOldSetMenuItemText)(hMenu, item, theString);
}
static void RandomMenuStyle(MenuHandle hMenu)
{
short itemCount = CountMItems(hMenu);
for(int i = 1; i <= itemCount; i++)
{
RandomMenuItemStyle(hMenu, i);
}
}
//---------------------------------------------------------------------------
// The patch functions
//---------------------------------------------------------------------------
static pascal void MyInsertMenu(MenuRef theMenu, short beforeID)
{
// Set up A4 globals
EnterCallback();
// First check to see if we have a task menu yet
if(!GetMenuHandle(kTaskMenuID))
{
Str255 menuTitle = "\p0 - ROM / System";
if(!IsFinder())
{
// Replace the menu title with a fake task number and app name
static int fakeTaskNum = 1;
NumToString(fakeTaskNum++, menuTitle);
menuTitle[++menuTitle[0]] = ' ';
menuTitle[++menuTitle[0]] = '-';
menuTitle[++menuTitle[0]] = ' ';
BlockMoveData(LMGetCurApName() + 1, menuTitle + menuTitle[0] + 1, LMGetCurApName()[0]);
menuTitle[0] += LMGetCurApName()[0];
}
MenuHandle hTaskMenu = NewMenu(kTaskMenuID, menuTitle);
int i = 1;
InsertMenuItem(hTaskMenu, "\p(Class Tree Of …", i++);
InsertMenuItem(hTaskMenu, "\p(Objects by Time", i++);
InsertMenuItem(hTaskMenu, "\p(Objects by Class", i++);
InsertMenuItem(hTaskMenu, "\p(Objects of …", i++);
InsertMenuItem(hTaskMenu, "\p(Methods of …/Ω", i++);
InsertMenuItem(hTaskMenu, "\p(-", i++);
InsertMenuItem(hTaskMenu, "\p(Break on Ref to Class …", i++);
InsertMenuItem(hTaskMenu, "\p(-", i++);
InsertMenuItem(hTaskMenu, "\p(option-Click for WindowList", i++);
// Use the unpatched insert menu to add this menu
(*gOldInsertMenu)(hTaskMenu, 0);
}
// If the title is Special, change it
if(PStrEqu(theMenu[0]->menuData, "\pSpecial"))
SetMenuTitle(theMenu, "\pSadoMasochism");
// If we're adding to the end, add it before the task menu
if(beforeID == 0)
beforeID = kTaskMenuID;
// Fiddle with the menu capitalization
RandomMenuStyle(theMenu);
// Call the original routine
(*gOldInsertMenu)(theMenu, beforeID);
// Retitle the Apple Menu
RetitleAppleMenu();
// Tear down A4 globals
ExitCallback();
}
static pascal void MySystemTask(void)
{
// Set up A4 globals
EnterCallback();
// Retitle the apple menu every few ticks
static long lastTick = 0;
if((TickCount() - lastTick) >= kUpdateTicks)
{
lastTick = TickCount();
RetitleAppleMenu();
}
// Call the original routine
(*gOldSystemTask)();
// Tear down A4 globals
ExitCallback();
}
static Handle GetResourceFromMyFile ( ResType rType, short rID )
{
short refNum = CurResFile();
Handle theHandle;
UseResFile ( gMyRefNum );
theHandle = Get1Resource ( rType, rID );
UseResFile ( refNum );
return theHandle;
}
static pascal Handle MyGetResource(ResType rType, short rID)
{
// Set up A4 globals
EnterCallback();
unsigned char oldRomMapInsert = LMGetROMMapInsert();
unsigned char oldTmpResLoad = LMGetTmpResLoad();
Handle hResult = NULL;
Boolean done = false;
switch ( rType )
{
// Load our mctb 0 for green menus and WDEF 0 for window locking
case 'mctb':
case 'WDEF':
if( rID == 0 )
{
hResult = GetResourceFromMyFile(rType, rID);
if(hResult)
done = true;
}
break;
// ppat 16 should load our simple grey pattern
case 'ppat':
if( rID == 16 )
{
hResult = GetResourceFromMyFile(rType, rID);
if(hResult)
done = true;
}
break;
}
if ( !done ) {
LMSetROMMapInsert(oldRomMapInsert);
LMSetTmpResLoad(oldTmpResLoad);
hResult = (*gOldGetResource)(rType, rID);
}
// Tear down A4 globals
ExitCallback();
return hResult;
}
static pascal void MySetMenuItemText(MenuRef theMenu, short item, ConstStr255Param itemString)
{
// Set up A4 globals
EnterCallback();
// Call the original routine
(*gOldSetMenuItemText)(theMenu, item, itemString);
// Update the random adornments
RandomMenuItemStyle(theMenu, item);
// Tear down A4 globals
ExitCallback();
}
static pascal long MyMenuSelect(Point startPt)
{
// Set up A4 globals
EnterCallback();
// Call the original routine
long result = (*gOldMenuSelect)(startPt);
if(result == 0)
{
// Check if we were in disabled task menu
if((MenuChoice() & 0xFFFF0000) == (-834 << 16))
{
Alert(-834, NULL);
}
}
// Tear down A4 globals
ExitCallback();
return result;
}
//---------------------------------------------------------------------------
// KeepMeAround keeps the resource fork open - taken from Aaron © 1995 Gregory D. Landweber.
//---------------------------------------------------------------------------
// 680x0 code only
/* Code to keep an INIT file opened at boot time around all the time, à la
SuitCase II et al. */
typedef struct _res_map res_map;
typedef struct _res_map *res_map_ptr;
typedef struct _res_map **res_map_handle;
struct _res_map {
long void1; /* Reserved */
long void2; /* Reserved */
long void3; /* Reserved */
long void4; /* Reserved */
res_map_handle next_map; /* Handle of next resource map */
short refNum; /* fRefNum for this file */
short fileAttrs; /* Resource file attributes for this file */
short tlOffset; /* Type List Offset from beginning of map */
short nlOffset; /* Name List Offset from beginning of map */
};
static void KeepMeAround ( short refNum )
{
THz saved_zone;
res_map_handle map_copy;
res_map_handle the_map;
the_map = (res_map_handle)LMGetTopMapHndl();
if ( (*the_map)->refNum == refNum ) {
map_copy = the_map;
LMSetTopMapHndl ( (Handle) (*the_map)->next_map );
}
else {
map_copy = (*the_map)->next_map;
while ( (*map_copy)->refNum != refNum ) {
the_map = map_copy;
map_copy = (*the_map)->next_map;
}
(*the_map)->next_map = (*map_copy)->next_map;
the_map = map_copy;
}
saved_zone = GetZone();
SetZone ( LMGetSysZone() );
HandToHand ( (Handle *)&map_copy );
SetZone(saved_zone);
DisposeHandle((Handle)the_map);
the_map = (res_map_handle)LMGetSysMapHndl();
while ( (*the_map)->next_map )
the_map = (*the_map)->next_map;
(*the_map)->next_map = map_copy;
(*map_copy)->next_map = nil;
}
//---------------------------------------------------------------------------
// The INIT main and patch installer.
//---------------------------------------------------------------------------
// Undocumented calls that ensure that a resource file opened will not be closed
pascal OSErr TurnSystemModeOn(void) = {0x3F3c, 0x0040, 0xa88f};
pascal OSErr TurnSystemModeOff(void) = {0x3F3c, 0x0041, 0xa88f};
int main(void)
{
EnterCodeResource(); // Set up for globals
PrepareCallback();
short refNum = CurResFile();
Handle hShowInit = Get1Resource('Code', 7000);
if (hShowInit)
((pascal void (*) (short, Boolean)) *hShowInit) (kIconFamilyID, true);
ReleaseResource(hShowInit);
// Set up the patch - the INIT *must* be in the Sysheap
Handle hInit0 = Get1Resource('INIT',0);
if (hInit0)
{
// Detach and lock the patch
DetachResource(hInit0);
HLock(hInit0);
HNoPurge(hInit0);
// Get the old address
gOldInsertMenu = (InsertMenuProcPtr)NGetTrapAddress(_InsertMenu, ToolTrap);
gOldSystemTask = (SystemTaskProcPtr)NGetTrapAddress(_SystemTask, ToolTrap);
gOldGetResource = (GetResourceProcPtr)NGetTrapAddress(_GetResource, ToolTrap);
gOldSetMenuItemText = (SetMenuItemTextProcPtr)NGetTrapAddress(_SetMenuItemText, ToolTrap);
gOldMenuSelect = (MenuSelectProcPtr)NGetTrapAddress(_MenuSelect, ToolTrap);
// Install the patch
NSetTrapAddress((UniversalProcPtr)&MyInsertMenu, _InsertMenu, ToolTrap);
NSetTrapAddress((UniversalProcPtr)&MySystemTask, _SystemTask, ToolTrap);
NSetTrapAddress((UniversalProcPtr)&MyGetResource, _GetResource, ToolTrap);
NSetTrapAddress((UniversalProcPtr)&MySetMenuItemText, _SetMenuItemText, ToolTrap);
NSetTrapAddress((UniversalProcPtr)&MyMenuSelect, _MenuSelect, ToolTrap);
}
// Find our resource file
FCBPBRec parms;
parms.ioFCBIndx = 0;
parms.ioRefNum = refNum;
OS_VERIFY(PBGetFCBInfoSync(&parms));
gMyRefNum = HOpenResFile(parms.ioVRefNum, parms.ioFCBParID, parms.ioNamePtr, fsRdPerm);
OS_VERIFY(ResError());
KeepMeAround(gMyRefNum);
ExitCodeResource(); // Shutdown use of globals (A4).
return 0;
}